interface pipeline_if ();
    logic [7:0] data;
    logic       valid;
    logic       ready;

    // Master 视角
    modport master(
        output  data,  // 传给下游
        output  valid, // 传给下游
        input   ready  // 下游传入
    );
    // Slave 视角
    modport slave(
        input   data,  // 上游传入
        input   valid, // 上游传入
        output  ready  // 传给上游
    );

endinterface

module pipeline_stage (
        input logic         clk,
        input logic         rst,
        pipeline_if.slave   sbus,
        pipeline_if.master  mbus
    );

    logic       ready;
    logic       valid;
    logic [7:0] data;

    // 当前流水级是否完成对数据的处理
    assign ready = 1'b1;

    // 通知上游是否可接收数据
    // 通知上游可接受数据的条件: 当前流水级数据无效 或 当前流水级任务完成且下游可接受数据
    assign sbus.ready = (~ valid) | (ready & mbus.ready);

    // 通知下游数据是否有效
    // 通知下游数据有效的条件: 当前流水级数据有效 且 当前流水级完成对数据的处理
    // 当前流水级是否有效, 取决于上一级传入的数据是否有效
    assign mbus.valid = valid & ready;

    always_ff @(posedge clk) begin
        if (rst) begin
            valid <= 1'b0;
            data  <= 8'b0;
        end
        else if (sbus.ready) begin
            valid <= sbus.valid;
            data  <= sbus.valid ? sbus.data : data;
        end
    end

    assign mbus.data = data;

endmodule


module pipeline_tb;
    logic clk;
    logic rst;

    // 生成时钟
    initial begin
        clk = 0;
        forever #1 clk = ~clk;
    end

    // 产生复位信号
    initial begin
        rst = 1;
        repeat(3) @(negedge clk);
        rst = 0;
    end

    // 创建流水线接口实例
    pipeline_if pipe_if_0();  // Source -> Stage1
    pipeline_if pipe_if_1();  // Stage1 -> Stage2
    pipeline_if pipe_if_2();  // Stage2 -> Stage3
    pipeline_if pipe_if_3();  // Stage3 -> Target

    // 实例化流水线模块
    pipeline_stage u_stage1(
        .clk(clk),
        .rst(rst),
        .sbus(pipe_if_0),
        .mbus(pipe_if_1)
    );

    pipeline_stage u_stage2(
        .clk(clk),
        .rst(rst),
        .sbus(pipe_if_1),
        .mbus(pipe_if_2)
    );

    pipeline_stage u_stage3(
        .clk(clk),
        .rst(rst),
        .sbus(pipe_if_2),
        .mbus(pipe_if_3)
    );

    logic [7:0] send_queue [$];
    logic [7:0] next_data;
    logic [7:0] expt_data;

    initial begin: send_data
        // 初始化接口信号
        pipe_if_0.data  <= 8'h0;
        pipe_if_0.valid <= 1'b0;

        wait(~rst); // 等待复位结束
        @(negedge clk); // 等待一个时钟周期

        $display("Reset released, start driving data");

        // 持续驱动数据
        pipe_if_0.valid = 1'b1;  // valid持续有效

        for (int i = 0; i < 100000; i++) begin
            // 当检测到ready有效时传输并更新数据
            if (pipe_if_0.ready & pipe_if_0.valid) begin
                next_data = $urandom_range(0, 255);
                pipe_if_0.data <= next_data;
                send_queue.push_back(next_data);
                $display("@%g: Send Data: 0x%x", $time, next_data);
            end
            @(negedge clk); // 在时钟下降沿驱动数据
        end

        pipe_if_0.valid <= 1'b0;
        @(negedge clk);
    end

    initial begin: recv_data
        // 初始化接口信号
        pipe_if_3.ready = 1'b1;

        // 等待数据传输完成
        forever begin
            @(negedge clk);
            if (pipe_if_3.valid & pipe_if_3.ready) begin
                if (send_queue.size() == 0) begin
                   $error("Unexpected data received");
                   $finish;
                end
                $display("@%g: Recv Data: 0x%x", $time, pipe_if_3.data);
                expt_data = send_queue.pop_front();
                if (pipe_if_3.data != expt_data) begin
                    $display("@%g: Error: Data mismatch", $time);
                    $display("expt_data: 0x%x, recv_data: 0x%x", expt_data, pipe_if_3.data);
                    $finish;
                end
            end
        end

        pipe_if_3.ready <= 1'b0;
        @(negedge clk);
    end


    initial begin
        $dumpfile("output.vcd");
        $dumpvars(0, pipeline_tb);
        #10000;
        $finish;
    end
endmodule
